package ink.metoo.auto.fishpi.chatroom.command

import com.google.gson.Gson
import ink.metoo.auto.fishpi.call.ChatRoomCall
import ink.metoo.auto.fishpi.call.Requests
import ink.metoo.auto.fishpi.chatroom.Message
import okhttp3.OkHttpClient
import okhttp3.Request

class QueryWeatherCommand : Command {

    override val commandText: String = "/天气"

    override val commandTypes: Array<Command.Type> = arrayOf(Command.Type.OTHER_CLIENT)

    override fun execute(message: Message) {
        val params = message.commandParams
        val province = params.getOrNull(1) ?: return
        val city = params.getOrNull(2) ?: province
        val county = params.getOrNull(3)
        doWeather(province, city, county)
    }

    private class ApiResult {
        var data: Any? = null
        var status: Int? = null
        var message: String? = null
    }

    private fun likeCity(city: String): List<String> {
        val url = "https://wis.qq.com/city/like?source=pc&city=${city}"
        val data = request(url)
        return data.asIterable().first().value.toString().split(", ")
    }

    @Suppress("UNCHECKED_CAST", "UNCHECKED_CAST")
    private fun doWeather(province: String, city: String, county: String?) {
        var url =
            "https://wis.qq.com/weather/common?source=pc&weather_type=observe|forecast_24h|index&province=${province}&city=${city}"
        if (county != null) {
            url += "&county=${county}"
        }
        val data = request(url)
        val index = data["index"] as Map<String, *>
        val randomIndex = index.entries.random().value as Map<String, *>
        val f24h = data["forecast_24h"] as Map<String, *>
        val f24h_3 = arrayOf(f24h["1"], f24h["2"], f24h["3"])
        val d = randomIndex["detail"].toString()
        var st = d.substring(0, 20)
        if (d.length > 20) {
            st += "\n"
            st += d.substring(20)
        }
        val content = mapOf(
            "t" to "${arrayOf(province, city, county).distinct().filterNotNull().joinToString("-")}天气",
            "st" to st,
            "date" to zip(f24h_3, "time") { it.substring(5) },
            "max" to zip(f24h_3, "max_degree"),
            "min" to zip(f24h_3, "min_degree"),
            "weatherCode" to zip(f24h_3, "night_weather_short") {
                return@zip reversedWeatherMap[it]?.get(0) ?: if (it.contains("雨")) "MODERATE_RAIN" else "UNKNOWN"
            },
            "msgType" to "weather",
            "type" to "weather"
        )
        ChatRoomCall.sendMessage("[weather]" + gson.toJson(content) + "[/weather]", false)
    }

    @Suppress("UNCHECKED_CAST", "UNCHECKED_CAST")
    private fun zip(objs: Array<Any?>, f: String, mapFun: (String) -> String = { it }): String {
        return objs.joinToString(",") {
            val itMap = it as Map<String, *>
            val s = itMap[f] as String
            return@joinToString mapFun(s)
        }
    }

    private fun request(url: String): Map<String, *> {
        val request = Request.Builder()
            .get()
            .url(url)
            .build()
        val call = okHttpClient.newCall(request)
        val rt = Requests.asJson(call, ApiResult::class)
        @Suppress("UNCHECKED_CAST", "UNCHECKED_CAST")
        return rt.data as Map<String, *>
    }


    companion object {

        private val gson = Gson()
        private val okHttpClient = OkHttpClient()

        private val weatherStatusMap = mapOf(
            "CLEAR_DAY" to "晴",
            "CLEAR_NIGHT" to "晴",
            "PARTLY_CLOUDY_DAY" to "多云",
            "PARTLY_CLOUDY_NIGHT" to "多云",
            "CLOUDY" to "阴",
            "LIGHT_HAZE" to "轻度雾霾",
            "MODERATE_HAZE" to "中度雾霾",
            "HEAVY_HAZE" to "重度雾霾",
            "LIGHT_RAIN" to "小雨",
            "MODERATE_RAIN" to "中雨",
            "HEAVY_RAIN" to "大雨",
            "STORM_RAIN" to "暴雨",
            "FOG" to "雾",
            "LIGHT_SNOW" to "小雪",
            "MODERATE_SNOW" to "中雪",
            "HEAVY_SNOW" to "大雪",
            "STORM_SNOW" to "暴雪",
            "DUST" to "浮尘",
            "SAND" to "沙尘",
            "WIND" to "大风"
        )

        private val reversedWeatherMap = mapOf(
            "晴" to listOf("CLEAR_DAY", "CLEAR_NIGHT"),
            "多云" to listOf("PARTLY_CLOUDY_DAY", "PARTLY_CLOUDY_NIGHT"),
            "阴" to listOf("CLOUDY"),
            "轻度雾霾" to listOf("LIGHT_HAZE"),
            "中度雾霾" to listOf("MODERATE_HAZE"),
            "重度雾霾" to listOf("HEAVY_HAZE"),
            "小雨" to listOf("LIGHT_RAIN"),
            "中雨" to listOf("MODERATE_RAIN"),
            "大雨" to listOf("HEAVY_RAIN"),
            "暴雨" to listOf("STORM_RAIN"),
            "雾" to listOf("FOG"),
            "小雪" to listOf("LIGHT_SNOW"),
            "中雪" to listOf("MODERATE_SNOW"),
            "大雪" to listOf("HEAVY_SNOW"),
            "暴雪" to listOf("STORM_SNOW"),
            "浮尘" to listOf("DUST"),
            "沙尘" to listOf("SAND"),
            "大风" to listOf("WIND")
        )

    }

}